﻿using System.Buffers;
using System.Diagnostics;
using System.Globalization;
using System.Reflection;
using System.Text;
using System.Text.Encodings.Web;
using System.Text.Json;
using System.Text.Json.Serialization;
using static LightCAD.Three.ImageBitmapLoader;

namespace LightCAD.Core
{
    public partial class LcDocument
    {

        #region static

        /// <summary>
        /// 创建 LcDocument 对象
        /// </summary>
        /// <returns></returns>
        public static LcDocument Create()
        {
            var doc = new LcDocument();
            doc.Initialize();
            return doc;
        }

        //public static void SetCurrent(LcDocument document)
        //{
        //    LcDocument.Current = document;
        //}

        /// <summary>
        /// 将文件以 json 格式 保持起来
        /// </summary>
        /// <param name="doc"></param>
        /// <param name="filePath"></param>
        /// <returns></returns>
        public static bool Save(LcDocument doc, string filePath)
        {
            Debug.Assert(File.Exists(filePath));

            using var stream = new MemoryStream();
            ToJsonStream(doc, stream, true);
            var json = Encoding.UTF8.GetString(stream.ToArray());
            File.WriteAllText(filePath, json);
            return true;
        }

        /// <summary>
        /// 将文件以 json 格式 序列化
        /// </summary>
        /// <param name="doc"></param>
        /// <param name="indented">输出格式是否需要空格</param>
        /// <returns></returns>
        public static void ToJsonStream(LcDocument doc, Stream stream, bool indented = false)
        {
            var options = new JsonWriterOptions
            {
                Indented = indented
            };
            var soptions = new JsonSerializerOptions
            {
                DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingDefault,
                WriteIndented = indented,
                IncludeFields = true,
            };

            using var writer = new Utf8JsonWriter(stream, options);
            writer.WriteStartObject();
            writer.WriteStringProperty(nameof(Uuid), doc.Uuid);
            writer.WriteStringProperty(nameof(FilePath), doc.FilePath);
            writer.WriteObjectProperty(nameof(Info), doc.Info, soptions);
            writer.WriteObjectProperty(nameof(ProjectInfo), doc.ProjectInfo, soptions);
            writer.WriteVector2dProperty(nameof(InsertPoint), doc.InsertPoint);

            doc.RefreshUsedTypes();
            writer.WriteCollectionProperty(nameof(UsedTypes), doc.UsedTypes, soptions);
            //ObjectPropertiesMap
            //PluginMap
            writer.WriteCollectionProperty(nameof(Components), doc.Components, soptions);
            writer.WriteCollectionProperty(nameof(UCSs), doc.UCSs, soptions);


            //TextStyle
            writer.WriteCollectionProperty(nameof(Blocks), doc.Blocks, null, (w, blk) => w.WriteBlockObject(blk, soptions));
            //Xrefs

            writer.WriteCollectionProperty(nameof(Layers), doc.Layers, soptions);
            //Views->View3Ds
            //Layouts取消
            writer.WriteCollectionProperty(nameof(Buildings), doc.Buildings, soptions);
            writer.WriteCollectionProperty(nameof(DrawingFrames), doc.DrawingFrames, soptions);
            //writer.WriteCollectionProperty(nameof(Profiles), doc.Profiles, soptions);

            writer.WriteElementSetProperty(nameof(ModelSpace), doc.ModelSpace, soptions);

            writer.WriteEndObject();

            writer.Flush();

        }



        internal static LcDocument FromJsonStream(Stream stream)
        {
            JsonDocument jsonDoc = JsonDocument.Parse(stream);

            var doc = new LcDocument();
            doc.Initialize();

            var docEle = jsonDoc.RootElement;
            doc.Uuid = docEle.ReadStringProperty(nameof(doc.Uuid));
            doc.FilePath = docEle.ReadStringProperty(nameof(FilePath));
            doc.Info = docEle.ReadObjectProperty<LcDocumentInfo>(nameof(Info));
            doc.ProjectInfo = docEle.ReadObjectProperty<LcProjectInfo>(nameof(ProjectInfo));
            doc.InsertPoint = docEle.ReadVector2dProperty(nameof(InsertPoint));

            var usedTypes = docEle.ReadCollectionProperty<ElementTypeCollection, ElementType>(nameof(UsedTypes),null);
            if (usedTypes != null) { doc.UsedTypes = usedTypes; }

            var components = docEle.ReadCollectionProperty<ComponentCollection, LcComponent>(nameof(Components), doc);
            if (components != null) { doc.Components = components; }

            var ucss = docEle.ReadCollectionProperty<UCSCollection, LcUCS>(nameof(UCSs), doc);
            if (ucss != null) { doc.UCSs = ucss; }
            //TextStyle

            var blocks = docEle.ReadCollectionProperty<LcBlockCollection, LcBlock>(nameof(Blocks), doc);
            if (blocks != null) { doc.Blocks = blocks; }
            //Xrefs

            var layers = docEle.ReadCollectionProperty<LayerCollection, LcLayer>(nameof(Layers), doc);
            if (layers != null) { doc.Layers = layers; }
            //Views->View3Ds
            //Layouts取消
            var buildings = docEle.ReadCollectionProperty<BuildingCollection, LcBuilding>(nameof(Buildings), doc);
            if (buildings != null) { doc.Buildings = buildings; }

            var drawingFrames = docEle.ReadCollectionProperty<LcDrawingFrameCollection, LcDrawingFrame>(nameof(DrawingFrames), doc);
            if(drawingFrames != null) { doc.DrawingFrames = drawingFrames; }
            //writer.WriteCollectionProperty(nameof(Profiles), doc.Profiles, soptions);

            doc.ModelSpace = doc.CreateObject<LcModelSpace>();
            doc.ModelSpace.Elements = docEle.ReadElementSetProperty(nameof(ModelSpace), doc);

            return doc;
        }


        /// <summary>
        /// UI及主要操作版本号
        /// #ToDo 
        /// </summary>
        /// 
        public const string Version = "1.0";

        /// <summary>
        /// 文件版本号(新增)
        /// #ToDo 需要考虑文件版本升级的兼容性
        /// </summary>
        public const string SerializationVersion = "1.0";

        //[JsonIgnore]
        //public static LcDocument Current { get; private set; }

        public static List<string> RegistAssemblies = new List<string>()
        {
            "LightCAD.Drawing"
        };

        /// <summary>
        /// 元素的活动处理器对象，由外部初始化确定
        /// </summary>
        public static Dictionary<ElementType, object> ElementActions { get; private set; } = new Dictionary<ElementType, object>();
        public static ElementTypeCollection ElementTypes = new ElementTypeCollection();

        #endregion

    }
}